const Service = require('egg').Service;
const websocket = require('nodejs-websocket');
const _clientConnections = {};
const MODULE_NAME = '数据同步';
let _instance = null;
let _connectionId = 1;

/**
 *
 */
class SocketService extends Service {
  constructor(app) {
    if (_instance) {
      throw new Error('单例模式，不能重复实例化！');
    }
    super(app);
    _instance = this;
    this._initialize = false;
    this._socketServer = null;
    this._isWorking = false;
  }

  static getInstance() {
    return _instance;
  }

  /**
   * 装箱返回的结果
   * @param {*} data
   * @param {*} code
   * @param {*} message
   */
  static wrapResult(data = null, { code = 0, message = null } = {}) {
    return JSON.stringify({ meta: { code: code, message }, data });
  }

  /**
   * 推送消息到客户端
   * @param {*} commentData
   */
  static pushMessages(
    { connectionId, messages = null, method } = {},
    onSucess = null
  ) {
    if (!messages || !connectionId) {
      return false;
    }
    if (!SocketService.isClientOnline(connectionId)) {
      // 坐席不在线，不推送消息
      return false;
    }

    const body = SocketService.wrapResult({
      method,
      data: messages,
    });
    const conn = SocketService.getClientConnection(connectionId);
    let successCounter = 0;
    if (conn) {
      try {
        conn.readyState === 1 &&
          conn.sendText(body, () => {
            successCounter++;
          });
      } catch (err) {
        _instance.logger.error(err);
      }
    }
    _instance.logger.info(`ws send data: ${body}`);
    if (successCounter > 0) {
      onSucess && onSucess();
    }
  }

  /**
   * 获取指定坐席客服的所有connection
   * @param {*} connectionId
   */
  static getClientConnection(connectionId) {
    const conn = _clientConnections[connectionId];
    return conn && conn.readyState === 1 ? conn : null;
  }

  /**
   * 判断指定connectionId的坐席客服是否在线
   * @param {*} connectionId
   */
  static isClientOnline(connectionId) {
    const conn = _clientConnections[connectionId];
    return conn && conn.readyState === 1;
  }

  get initialized() {
    return this._initialize;
  }

  // 获取已连接的用户id
  get connectedUsers() {
    return this._socketServer.connections.map((conn) => {
      return conn.connectionId;
    });
  }

  get logger() {
    return this.ctx.logger;
  }

  get dataSubscribeService() {
    return this.ctx.service.dataSubscribeService;
  }

  /**
   * 初始化服务
   * @param {*} port
   */
  async init(port = 3000) {
    const $this = this;
    const $logger = this.logger;
    if (this.initialized) {
      $logger.info(`【${MODULE_NAME}】服务已初始化`);
      return false;
    }
    this._initialize = true;
    $logger.info(
      `初始化【${MODULE_NAME}】服务，端口 = ${port}，pid = ${process.pid}`
    );

    try {
      this._socketServer = websocket
        .createServer((connection) => {
          connection.on('text', async (text) => {
            // $logger.info(`WS 接收消息：${text}`);
            try {
              const params = JSON.parse(text);
              const methodName = params.method;
              const method = $this[methodName];
              if (method) {
                const res = await method.call($this, connection, params.params);
                connection.sendText(res);
              } else {
                $this.fireError(connection, {
                  message: '无效的method',
                });
              }
            } catch (err) {
              $logger.error(err);
              $this.fireError(connection, {
                message: err.message,
              });
            }
          });

          connection.on('close', (code, reason) => {
            $logger.warn(
              `客户端：${connection.connectionId} 的客户端已关闭连接！code：${code}，reason：${reason}`
            );
            $this.disconnect(connection);
          });

          connection.on('error', (code, reason) => {
            $logger.error(
              `客户端：${connection.connectionId} 的客户端连接发生异常！code：${code}，reason：${reason}`
            );
            $this.disconnect(connection);
          });
        })
        .listen(port);

      $logger.info(`【${MODULE_NAME}】初始化完成`);
      return true;
    } catch (err) {
      $logger.error(`【${MODULE_NAME}】初始化失败`);
      $logger.error(err);
    }
    return false;
  }

  /**
   * 链接握手，保存userId与connection的关系
   * @param {*} connectionId 坐席客服的userId
   */
  async connect(connection, { connectionId }) {
    connection.connectionId = connectionId = connectionId || (`${Date.now()}${(_connectionId++)
      .toString()
      .padStart(6, '0')}`);
    _clientConnections[connectionId] = connection;
    this.logger.info(`坐席客服: ${connectionId} 已连接`);
    const res = SocketService.wrapResult({
      method: 'connectSuccess',
      data: {
        connectionId,
      },
    });
    return res;
  }

  /**
   * 坐席客服断开连接（正常或异常）
   * @param {*} connectionId
   */
  async disconnect({ connectionId }) {
    delete _clientConnections[connectionId];
  }

  /**
   * 响应客户端订阅数据消息
   */
  async subscribe(data) {
    this.dataSubscribeService.subscribe(data)
  }

  /**
   * 触发错误消息
   * @param {*} connection
   * @param {*} code
   * @param {*} message
   */
  fireError(connection, { code = 90000, message = 'error' } = {}) {
    const res = SocketService.wrapResult(null, { code, message });
    connection.sendText(JSON.stringify(res));
  }
}

module.exports = SocketService;
